<?php
/**
 * alltosun.com  log_observer.php
 * ============================================================================
 * 版权所有 (C) 2009-2014 北京互动阳光科技有限公司，并保留所有权利。
 * 网站地址:   http://www.alltosun.com
 * ----------------------------------------------------------------------------
 * 许可声明：这是一个开源程序，未经许可不得将本软件的整体或任何部分用于商业用途及再发布。
 * ============================================================================
 * $Author: 李维 (liw@alltosun.com) $
 * $Date: 2014-11-24 下午4:17:13 $
 * $Id$
*/

/**
 * 供框架调用的方法
 */
class log_observer
{
    // 驱动实例
    private static $driver = null;

    /**
     * 从配置文件中初始化log记录
     */
    public static function init_driver()
    {
        if(self::$driver !== null) return true;
        $driver_name = Config::get('log_observer_driver');
        $class_name  = 'log_observer_'.$driver_name;
        if(!class_exists($class_name)) {
            throw new AnMessageException('log_observer::init_driver failed: log_observer_driver not support');
        }
        self::$driver = new $class_name();
        return true;
    }

    /**
     * 解析res参数
     */
    public static function parse_res($res)
    {
        $res_name = !empty($res[0]) ? $res[0] : '';
        $id       = !empty($res[1]) ? $res[1] : 0;
        $info     = !empty($res[2]) ? $res[2] : array();

        $res_info = array();
        if($res_name && $id > 0) {
            $res_info = _model($res_name)->read($id);
        }

        // 写入log的文件
        return array(
                        'res_name'    => $res_name,
                        'id'          => $id,
                        'info'        => $info,
                        'res_info'    => $res_info,
                        'add_time'    => date('Y-m-d H:i:s'),
                        'op_id'       => user_helper::get_user_id(),
                        'ip'          => Request::getClientIp(),
                        'server_info' => $_SERVER,
                        'post'        => $_POST,
                        'get'         => $_GET
        );
    }

    /**
     * 创建的log记录
     * @param string $res_name
     * @param int $id
     * @param array $info
     */
    public static function write_createBEF_log($res)
    {
        $res = self::parse_res($res);
        self::init_driver();
        return self::$driver->write_log('createBEF', $res);
    }

    /**
     * 创建的log记录
     * @param string $res_name
     * @param int $id
     * @param array $info
     */
    public static function write_create_log($res)
    {
        $res = self::parse_res($res);
        self::init_driver();
        return self::$driver->write_log('create', $res);
    }

    /**
     *  更新之前的log记录
     * @param string $res_name
     * @param int $id
     * @param array $info
     */
    public static function write_updateBEF_log($res)
    {
        $res = self::parse_res($res);
        self::init_driver();
        return self::$driver->write_log('updateBEF', $res);
    }

    /**
     * 更新之后的log记录
     * @param string $res_name
     * @param int $id
     * @param array $info
     */
    public static function write_update_log($res)
    {
        $res = self::parse_res($res);
        self::init_driver();
        return self::$driver->write_log('update', $res);
    }

    /**
     * 删除的log记录
     * @param string $res_name
     * @param int $id
     * @param array $info
     */
    public static function write_deleteBEF_log($res)
    {
        $res = self::parse_res($res);
        self::init_driver();
        return self::$driver->write_log('deleteBEF', $res);
    }

    /**
     * 删除的log记录
     * @param string $res_name
     * @param int $id
     * @param array $info
     */
    public static function write_delete_log($res)
    {
        $res = self::parse_res($res);
        self::init_driver();
        return self::$driver->write_log('delete', $res);
    }

    /**
     * 获取log
     * @param string $res_name
     * @param int $res_id
     * @return array
     */
    public static function get_log($res_name, $res_id)
    {
        if(!$res_name || !$res_id) {
            return array();
        }
        self::init_driver();
        return self::$driver->get_log($res_name, $res_id);
    }

    /**
     * 合成log的文字说明
     * @return array
     */
    public static function generate_log($res_name, $res_id)
    {
        if(!$res_name || !$res_id) {
            return array();
        }
        self::init_driver();
        $log_list = self::$driver->get_log($res_name, $res_id);

        $log_type = array('create', 'update', 'delete');
        $log_message_list= array();
        foreach ($log_list as $k=>$v) {
            if(in_array($v['log_type'], $log_type)) {
                $log_message_list[] = self::generte_log_one($v);
            }
        }
        return $log_message_list;
    }

    /**
     * 合成单条的log记录
     */
    public static function generte_log_one($log_info)
    {
        if($log_info['op_id'] <= 0) {
            $op_name = "未知用户";
        } else {
            $op_name = user_helper::display_name($log_info['op_id']);
        }
        $content = '<p class="logmsg"><span class="logmsg-time">['.$log_info['add_time'].']</span>: <span class="logmsg-op-name">'.$op_name.'(UID='.$log_info["op_id"].', IP:'.$log_info["ip"].')</span>';

        if($log_info['log_type'] == 'create') {
            $content .= '在表<span class="logmsg-resname">'.$log_info['res_name'].'</span>中创建了记录<span class="logmsg-resid">'.$log_info['id'].'</span>';
        } elseif ($log_info['log_type'] == 'delete') {
            $content .= '在表<span class="logmsg-resname">'.$log_info['res_name'].'</span>中删除了记录<span class="logmsg-resid">'.$log_info['id'].'</span>';
        } elseif($log_info['log_type'] == 'update') {
            $content .= '在表<span class="logmsg-resname">'.$log_info['res_name'].'</span>中更新了记录<span class="logmsg-resid">'.$log_info['id'].'</span>';
            if(is_array($log_info['info']) && !empty($log_info['info'])) {
                $content .= '<span class="logmsg-fields">';
                foreach ($log_info['info'] as $k=>$v) {
                    $content .= '<br><span>将字段<label class="logmsg-field">'. $k . '</label>更新为<label class="logmsg-field-value">' . $v .'</label></span>';
                }
                $content .= '</span>';
            }
        }

        $url_content = '';
        if(!empty($log_info['server_info']['REQUEST_URI'])) {
            $url_content .= '<br/><span>request_uri: '.$log_info['server_info']['REQUEST_URI'].'</span>';
        }
        if(!empty($log_info['get']['anu'])) {
            $url_content .= '<br/><span>anu: '.$log_info['get']['anu'].'</span>';
        }

        //$hidden_content = '<span style="display:none;>'.htmlspecialchars(var_export($log_info, true)).'</span>';
        $hidden_content = '';
        return $content . $url_content . $hidden_content . '</p>';
    }
}



/////////////////////////
//  接口实现
/////////////////////////



/**
 * 文件log的实现方式
 */
class log_observer_file implements log_observer_wrapper
{
    // 目录起始年
    const START_YEAR     = 2013;
    const DELIMITER      = "##logstart==>";
    const REPLACEPATTERN = "/^(\#\#logstart\=\=\>)/";

    private $log_dir = '';
    private $err_msg = '';

    /**
     * 初始化
     */
    public function __construct()
    {
        $this->conf = Config::get('log_observer_driver_file');
        if(!empty($this->conf['log_dir'])) {
            $this->log_dir = rtrim($this->conf['log_dir'], '/');
        } else {
            throw new AnMessageException("log_observer_file __construct: log_dir not set");
        }
    }

    /**
     * 获取资源的log文件名
     */
    public function get_logfile($res_name, $res_id, $is_create_file = true)
    {
        if(!$res_name || !$res_id) {
            $this->err_msg = "get_logfile param empty";
            return false;
        }
        // 寻找以前的log文件，否则则创建
        $now_year = date('Y');
        $tmp_year = $now_year;
        $filename = $this->log_dir."/$res_name/$tmp_year/{$res_name}_{$res_id}.log";
        $file_exists = true;
        while(!file_exists($filename)) {
            if($tmp_year < self::START_YEAR) {
                $file_exists = false;
                break;
            }
            $tmp_year--;
            $filename = $this->log_dir."/$res_name/$tmp_year/{$res_name}_{$res_id}.log";
        }
        if(!$file_exists) {
            // 不创建，直接返回
            if(!$is_create_file) {
                $this->err_msg = "no log file found";
                return false;
            }

            $dir = $this->log_dir."/$res_name/$now_year";
            if(!is_dir($dir) && !mkdir($dir, 0700, true)) {
                $this->err_msg = "get_logfile create dir failed: ".$dir;
                return false;
            }
            $filename = "$dir/{$res_name}_{$res_id}.log";
            if(!touch($filename)) {
                $this->err_msg = "get_logfile touch failed";
                return false;
            }
        }
        return $filename;
    }

    /**
     * 写日志
     * @param string $type log类型
     * @param string $res_name 表名
     * @param multi  $id 主键
     * @param array $info
     */
    public function write_log($type, $res)
    {
        $res_name = $res['res_name'];
        $id       = $res['id'];

        $log_file = $this->get_logfile($res_name, $id);
        if(!$log_file) {
            throw new AnMessageException("write_log failed: ".$this->err_msg);
        }
        $res['log_type'] = $type;
        $content = self::DELIMITER . serialize($res);
        if(file_put_contents($log_file, $content, FILE_APPEND)) {
            return true;
        }
        throw new AnMessageException("write_log failed: file_put_contents failed");
    }

    /**
     * 获取日志
     * @param string $res_name 表名
     * @param multi  $id 主键
     * @return array
     */
    public function get_log($res_name, $id)
    {
        $filename = $this->get_logfile($res_name, $id, false);
        if(!$filename) {
            return array();
        }
        $content = file_get_contents($filename);
        if(!$content) {
            return array();
        }
        $content = preg_replace(self::REPLACEPATTERN, "", trim($content));
        $log_str_list = explode(self::DELIMITER, $content);
        $log_list = array();
        foreach ($log_str_list as $k=>$v) {
            $log_list[] = unserialize(trim($v));
        }
        return $log_list;
    }
}



/////////////////////////
//  接口声明
/////////////////////////



/**
 * 接口
 */
interface log_observer_wrapper
{
    /**
     * 写日志
     * @param string $type log类型
     * @param string $res_name 表名
     * @param multi  $id 主键
     * @param array $info
     */
    public function write_log($type, $res);

    /**
     * 获取日志
     * @param string $res_name 表名
     * @param multi  $id 主键
    */
    public function get_log($res_name, $id);
}
?>